<template>
  <view class="signature-wrap">
    <view
      class="img-wrap"
      @tap="showSignature()"
      @touchstart="touchSignature()"
    >
      <image :src="absPrevView" mode="scaleToFill"></image>
    </view>
    <view v-if="!disabled" v-show="show" class="signature-contain">
      <view class="signature-main" style="z-index: 3000">
        <view class="signature-title">
          <text v-for="t in titles" :key="t">{{ t }}</text>
        </view>
        <canvas
          disable-scroll="true"
          class="signature"
          :class="cid"
          canvas-id="cvs"
          @touchstart="touchstart"
          @touchmove="touchmove"
          @touchend="touchend"
        ></canvas>
        <view class="signature-btns">
          <view
            class="btn btn-cancel cu-btn bg-main margin-tb-sm text-white"
            @tap="cancelSignature()"
          >
            <text>取</text>
            <text>消</text>
          </view>
          <view
            class="btn btn-clear cu-btn bg-main margin-tb-sm text-white"
            @tap="clearSignature()"
          >
            <text>清</text>
            <text>空</text>
          </view>
          <view
            class="btn btn-ok cu-btn bg-main margin-tb-sm text-white"
            @tap="onOK()"
          >
            <text>确</text>
            <text>定</text>
          </view>
        </view>
      </view>
    </view>

    <canvas
      v-if="exportPngFlag"
      disable-scroll="true"
      class="signature-exportPng"
      canvas-id="exportPng"
      id="exportPng"
    />
  </view>
</template>

<script>
let _keyStr =
  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
var _utf8_encode = function (string) {
  string = string.replace(/\r\n/g, '\n')
  var utftext = ''
  for (var n = 0; n < string.length; n++) {
    var c = string.charCodeAt(n)
    if (c < 128) {
      utftext += String.fromCharCode(c)
    } else if (c > 127 && c < 2048) {
      utftext += String.fromCharCode((c >> 6) | 192)
      utftext += String.fromCharCode((c & 63) | 128)
    } else {
      utftext += String.fromCharCode((c >> 12) | 224)
      utftext += String.fromCharCode(((c >> 6) & 63) | 128)
      utftext += String.fromCharCode((c & 63) | 128)
    }
  }
  return utftext
}

let base64encode = function (input) {
  var output = ''
  var chr1, chr2, chr3, enc1, enc2, enc3, enc4
  var i = 0
  input = _utf8_encode(input)
  while (i < input.length) {
    chr1 = input.charCodeAt(i++)
    chr2 = input.charCodeAt(i++)
    chr3 = input.charCodeAt(i++)
    enc1 = chr1 >> 2
    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4)
    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6)
    enc4 = chr3 & 63
    if (isNaN(chr2)) {
      enc3 = enc4 = 64
    } else if (isNaN(chr3)) {
      enc4 = 64
    }
    output =
      output +
      _keyStr.charAt(enc1) +
      _keyStr.charAt(enc2) +
      _keyStr.charAt(enc3) +
      _keyStr.charAt(enc4)
  }
  return output
}
export default {
  cxt: null,
  data() {
    return {
      VERSION: '1.0.0',
      cid: 'cvs',
      show: false,
      ctrl: null,
      listeners: [],
      prevView: '',

      draws: [],
      lines: [],
      line: null,
      exportPngFlag: false
    }
  },
  props: {
    value: {
      default: ''
    },
    title: {
      type: String,
      default: '请签字'
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    value() {
      this.prevView = this.value
    }
  },
  computed: {
    titles() {
      return this.title.split('')
    },
    absPrevView() {
      var pv = this.prevView
      // if(pv){
      // 	pv = this.$wrapUrl(pv)
      // }
      return pv
    }
  },
  mounted() {
    this.prevView = this.value
  },
  methods: {
    // 将图片旋转90deg导出
    // async exportPng(png) {
    //   const { width, height } = await toPromise(uni.getImageInfo, {
    //     src: png
    //   })
    //
    //   const ctx = uni.createCanvasContext('exportPng', this)
    //   // 将图片旋转90deg绘制图片
    //   ctx.rotate((-90 * Math.PI) / 180)
    //   ctx.drawImage(png, -width, 0, width, height)
    //   ctx.restore()
    //   ctx.draw(true)
    //
    //   let count = 1
    //   while (count) {
    //     await selectQuery('#exportPng')
    //       .then(() => {
    //         count = 0
    //       })
    //       .catch(() => {
    //         count++
    //       })
    //
    //     await sleep(29)
    //
    //     console.log('count', count);
    //
    //     // about 1500ms
    //     if (count > 100) {
    //       count = 0
    //     }
    //   }
    //
    //   return new Promise((resolve, reject) => {
    //     uni.canvasToTempFilePath(
    //       {
    //         canvasId: 'exportPng',
    //         success: res => {
    //           resolve(res.tempFilePath)
    //         },
    //         fail: err => {
    //           reject(err)
    //         }
    //       },
    //       this
    //     )
    //   })
    // },
    async onOK() {
      const svgData = this.ctrl.getValue()

      this.prevView = svgData
      this.$emit('input', svgData)
      this.$emit('change', svgData)

      uni.showLoading({ title: '签名导出中...' })
      const pngUrl = await new Promise((resolve, reject) => {
        uni.canvasToTempFilePath(
          {
            canvasId: 'cvs',
            fileType: 'png',
            quality: 1,
            success: (res) => resolve(res.tempFilePath),
            fail: reject
          },
          this
        )
      })

      this.$emit('drawOk', pngUrl)
      this.hideSignature()
      let f = this.listeners.shift()
      if (f) f(pngUrl)

      // this.exportPngFlag = true
      // await sleep(29)
      // try {
      //   const imgUrl = await this.exportPng(pngUrl)
      //
      //   this.$emit('drawOk', imgUrl)
      //   this.hideSignature()
      //   let f = this.listeners.shift()
      //   if (f) f(imgUrl)
      // } finally {
      //   uni.hideLoading()
      //   this.exportPngFlag = false
      // }
    },
    // getPath() {
    //   uni.canvasToTempFilePath(
    //     {
    //       canvasId: 'cvs',
    //       fileType: 'png',
    //       quality: 1, //图片质量
    //       success: (res) => {
    //         this.$emit('drawOk', res.tempFilePath)
    //       }
    //     },
    //     this
    //   )
    // },

    touchSignature() {
      let sig = this.prevView
      if (!sig || !sig.length) {
        this.showSignature()
      }
    },
    showSignature() {
      if (this.disabled) return
      if (!this.ctrl) {
        this.initCtrl()
      } else if (!this.show) {
        this.clearSignature()
        this.show = true
      }
    },
    async getSyncSignature() {
      this.showSignature()
      return await new Promise(async (resolve, reject) => {
        this.listeners.push((res) => {
          resolve(res)
        })
      })
    },
    cancelSignature() {
      this.listeners.map((f) => {
        f(null)
      })
      this.hideSignature()
    },
    hideSignature() {
      this.ctrl && this.ctrl.clear()
      this.show = false
    },
    clearSignature() {
      this.ctrl && this.ctrl.clear()
    },
    async initCtrl() {
      this.show = true
      let cxt = uni.createCanvasContext(this.cid, this)
      this.cxt = cxt
      // cxt.clearRect(0,0,c.width,c.height);
      this.ctrl = {
        width: 0,
        height: 0,
        clear: () => {
          this.lines = []
          let info = uni
            .createSelectorQuery()
            .in(this)
            .select('.' + this.cid)
          info
            .boundingClientRect((data) => {
              if (data) {
                cxt.clearRect(0, 0, data.width, data.height)
                if (data.width && data.height) {
                  this.ctrl.width = data.width
                  this.ctrl.height = data.height
                }
              }
            })
            .exec()
          this.redraw()
        },
        getValue: () => {
          if (!this.lines.length) return ''
          let svg = this._get_svg()
          // new Buff
          let b64 = base64encode(svg)
          let data = 'data:image/svg+xml;base64,' + b64
          // console.log(svg);
          // console.log(data);
          return data
        }
      }
      this.$nextTick(function () {
        this.ctrl.clear()
      })
    },
    _get_svg() {
      let r = -90
      let paths = []
      let raww = this.ctrl.width
      let rawh = this.ctrl.height
      let width = Math.abs(r) != 90 ? raww : rawh
      let height = Math.abs(r) == 90 ? raww : rawh
      let cx = raww / 2
      let cy = rawh / 2
      let PI = Math.PI
      let R = (r || 0) % 360
      let cosv = Math.cos((R * PI) / 180)
      let sinv = Math.sin((R * PI) / 180)
      let dcx = (width - raww) / 2
      let dcy = (height - rawh) / 2
      let trans = function (p) {
        if (!R) {
          return p
        } else {
          let nx = (p.x - cx) * cosv - (p.y - cy) * sinv + cx
          let ny = (p.x - cx) * sinv + (p.y - cy) * cosv + cy
          return {
            x: nx + dcx,
            y: ny + dcy
          }
        }
        return p
      }
      this.lines.map((l) => {
        if (l.points.length < 2) {
          return
        }
        let sp = trans(l.start)
        let pts = [`M ${sp.x} ${Number(sp.y)}`]
        l.points.map((p) => {
          let np = trans(p)
          pts.push(`L ${np.x} ${Number(np.y)}`)
        })
        paths.push(
          `<path stroke-linejoin="round" stroke-linecap="round" stroke-width="3" stroke="rgb(0,0,0)" fill="none" d="${pts.join(
            ' '
          )}"/>`
        )
      })
      let svg = `<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${width}" height="${height}">${paths.join(
        '\n'
      )}</svg>`
      return svg
    },
    _get_svg_raw() {
      let paths = []
      this.lines.map((l) => {
        if (l.points.length < 2) {
          return
        }
        let pts = [`M ${l.start.x} ${Number(l.start.y)}`]
        l.points.map((p) => {
          pts.push(`L ${p.x} ${Number(p.y)}`)
        })
        paths.push(
          `<path stroke-linejoin="round" stroke-linecap="round" stroke-width="3" stroke="rgb(0,0,0)" fill="none" d="${pts.join(
            ' '
          )}"/>`
        )
      })
      let width = this.ctrl.width
      let height = this.ctrl.height
      let svg = `<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${width}" height="${height}" transform="rotate(-90)">${paths.join(
        '\n'
      )}</svg>`
      return svg
    },
    _get_point(e) {
      return {
        x: e.changedTouches[0].x.toFixed(1),
        y: e.changedTouches[0].y.toFixed(1)
      }
    },
    touchstart(e) {
      let p = this._get_point(e)
      this.line = {
        start: p,
        points: [p]
      }
      this.lines.push(this.line)
    },
    touchmove(e) {
      let p = this._get_point(e)
      this.line.points.push(p)
      if (!this.tm) {
        this.tm = setTimeout(() => {
          this.redraw()
          this.tm = 0
        }, 10)
      }
    },
    touchend(e) {
      let p = this._get_point(e)
      this.line.points.push(p)
      this.line.end = p
      this.redraw()
    },
    redraw() {
      let cxt = this.cxt
      cxt.setStrokeStyle('#000')
      cxt.setLineWidth(3)
      var last = null
      this.lines.map((l) => {
        cxt.beginPath()
        if (l.points.length < 2) {
          return
        }
        cxt.moveTo(l.start.x, l.start.y)
        l.points.map((p) => {
          cxt.lineTo(p.x, p.y)
        })
        cxt.stroke()
      })

      cxt.draw()
    },
    canvasIdErrorCallback: function (e) {
      console.error(e.detail.errMsg)
    }
  }
}
</script>

<style lang="scss">
.signature-wrap {
  height: 100%;
  width: 100%;
  // padding: 0 5px;

  // min-width: 60vw;
  .img-wrap {
    width: 100%;
    min-height: 200rpx;
    display: flex;
    align-items: center;
    text-align: center;
    align-content: center;
    justify-content: center;

    image {
      width: 100%;
    }

    // background: red;
  }
}

.signature-contain {
  z-index: 9000;
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;

  .signature-main {
    background: white;
    flex-direction: row-reverse;
    display: flex;
    align-items: stretch;
    height: 101%;
    overflow: scroll;
  }

  .signature-title {
    font-weight: bold;
    font-size: 18px;
    display: flex;
    padding: 0 20rpx;
    flex-direction: column;
    justify-content: center;
    height: 100vh;
    color: $uni-text-color;

    text {
      transform: rotate(90deg);
    }
  }

  .signature {
    border: 1px dotted black;
    border-bottom: 1px dotted black;
    background: #fff;
    margin: 10px 0;
    width: 90vw;
    height: 90vh;
    align-self: center;
    // pointer-events:none;
  }

  .signature-btns {
    display: flex;
    padding: 2px;
    // margin-right: 5px;
    flex-direction: column;

    .btn {
      flex-grow: 1;
      flex-shrink: 0;
      padding: 20rpx;
      font-size: 20px;
      margin: 0;
      text-align: center;
      text-decoration: none;
      height: 30vh;
      display: flex;
      align-content: center;
      justify-content: center;
      flex-direction: column;

      text {
        transform: rotate(90deg);
      }

      & + .btn {
        border-top: 1px solid #eee;
      }

      &.btn-clear {
        // background-color: #fc2a07;
        color: $uni-color-success;
      }

      &.btn-cancel {
        // background-color: #eff4f4;
        color: $uni-color-warning;
      }

      &.btn-ok {
        // background-color: $uni-color-success;
        color: $uni-color-primary;
      }
    }
  }
}

.signature-exportPng {
  position: fixed;
  top: 0;
  left: 0;
  width: 90vh;
  height: 90vw;
  z-index: 999999;
  border: 2rpx solid red;
  transform: translate3d(9999px, 9999px, 9999px);
}
</style>
